use std::collections::HashMap;
use std::fs;
use std::path::Path;

use serde::{Deserialize, Serialize};
use crate::runtime::runtime::error::InternalError;
use crate::runtime::runtime::result::InternalErrorResult;

pub const NULL_VALUE: &'static str = "DEMNULL";

#[derive(Debug, Serialize, Deserialize)]
pub struct Tool {
    name: String,
    version: String,
    environments: HashMap<String, String>,
}

impl Tool {
    /// 返回工具名称
    pub fn name(&self) -> &str {
        self.name.as_str()
    }

    /// 返回工具版本
    pub fn version(&self) -> &str {
        self.version.as_str()
    }

    /// 返回工具定义的环境变量
    pub fn environments(&self) -> &HashMap<String, String> {
        &self.environments
    }

    /// 设置工具的环境变量
    pub fn set_environment(&mut self, name: String, value: String) -> InternalErrorResult<()> {
        self.environments.insert(name, value);

        Ok(())
    }
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct Environment {
    // 配置路径
    #[serde(skip)]
    pub config_path: String,

    // 软件配置表
    software: HashMap<String, String>,
    // 环境配置表
    environments: HashMap<String, HashMap<String, String>>,
}

impl Environment {
    /// new
    pub fn new<P: AsRef<Path>>(config_path: P) -> Environment {
        Environment { config_path: config_path.as_ref().to_str().unwrap().to_string(), software: Default::default(), environments: Default::default() }
    }

    /// 检查给定的软件名称是否已设置
    pub fn is_set(&self, name: &str) -> bool {
        self.software.get(name).is_some()
    }

    /// 获取软件配置表
    pub fn get_software(&self) -> &HashMap<String, String> {
        &self.software
    }

    /// 获取给定软件配置的环境变量表
    pub fn get_environments(&self, name: &str) -> Option<&HashMap<String, String>> {
        self.environments.get(name)
    }

    /// 设置软件的环境变量
    pub fn set_environment(&mut self, name: &str, key: String, value: String) -> InternalErrorResult<()> {
        if self.environments.get(name).is_some() {
            let environments = self.environments.get_mut(name).unwrap();
            environments.insert(key, value);

            return self.sync_to_disk();
        }

        let mut environments: HashMap<String, String> = HashMap::new();
        environments.insert(key, value);

        self.environments.insert(name.to_string(), environments.clone());

        self.sync_to_disk()
    }

    /// 移除软件的环境变量
    pub fn unset_environment(&mut self, name: &str, key: &str) -> InternalErrorResult<()> {
        if self.environments.get(name).is_some() {
            let environments = self.environments.get_mut(name).unwrap();
            environments.remove(key);

            return self.sync_to_disk();
        }

        Ok(())
    }

    /// 切换软件版本
    pub fn switch_to(&mut self, name: String, version: String) -> InternalErrorResult<()> {
        self.software.insert(name, version);

        self.sync_to_disk()
    }

    /// 在当前环境移除软件的指定版本
    pub fn remove(&mut self, name: &str, version: &str) -> InternalErrorResult<()> {
        let value = self.software.get(name);
        if value.is_some() && value.unwrap() == version {
            self.software.remove(name);

            return self.sync_to_disk();
        }

        Ok(())
    }

    /// 保存到磁盘
    fn sync_to_disk(&self) -> InternalErrorResult<()> {
        let content = serde_json::to_string(self).map_err(|e| InternalError::new(format!("Failed to serialize environment: {}", e.to_string())))?;
        fs::write(self.config_path.as_str(), content).map_err(|e| InternalError::new(format!("failed to write to file: {}. err: {}", self.config_path.as_str(), e.to_string())))?;

        Ok(())
    }
}

impl AsRef<Environment> for Environment {
    fn as_ref(&self) -> &Environment {
        self
    }
}

impl AsMut<Environment> for Environment {
    fn as_mut(&mut self) -> &mut Environment {
        self
    }
}